package com.mikelouis.test.scala.proginscala.chapter21

/**
 * Created by yuazhu on 2/1/2015.
 */
object ImplicitParameterTest3 {
  def main(args: Array[String]) {
//    implicit def predefStringWrapperRevealed(s: String): Ordered[String] =
//      Predef.stringWrapper(s)
    // compiler implicitly add Int=>Ordered[Int]
    println(maxListImpParm(List(1,5,10,3)))
    println(maxListImpParm(List(1.5, 5.2, 10.7, 3.14159)))
    println(maxListImpParm(List("one", "two", "three")))
  }

  /**
   * T must be extends Ordered[T], so is not applicable for Ordered[Int], Ordered[String], etc
   * @param elements
   * @tparam T
   * @return
   */
  def maxListUpBound[T <: Ordered[T]](elements: List[T]): T =
    elements match {
      case List() => throw new IllegalArgumentException("empty list!")
      case List(x) => x
      case x :: rest =>
        val maxRest = maxListUpBound(rest)
        if (x > maxRest) x
        else maxRest
    }

  /**
   *
   * @param elements
   * @param orderer method to convert T to Ordered[T] type
   * @tparam T
   * @return
   */
  def maxListImpParm[T](elements: List[T])
                       (implicit orderer: T => Ordered[T]): T =
    elements match {
      case List() =>
        throw new IllegalArgumentException("empty list!")
      case List(x) => x
      case x :: rest =>
        val maxRest = maxListImpParm(rest)(orderer)
        if (orderer(x) > maxRest) x
        else maxRest
    }

  /**
   *  implicitly convert orderer
   * @param elements
   * @param orderer
   * @tparam T
   * @return
   */
  def maxList[T](elements: List[T])
                       (implicit orderer: T => Ordered[T]): T =
    elements match {
      case List() =>
        throw new IllegalArgumentException("empty list!")
      case List(x) => x
      case x :: rest =>
        val maxRest = maxListImpParm(rest)  // implicit convert to orderer
        if (x > maxRest) x                  // implicitly convert to orderer(x)
        else maxRest
    }
}
